﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.Diagnostics;
using Microsoft.WindowsAzure.Diagnostics.Management;
using Microsoft.WindowsAzure.ServiceRuntime;
using Microsoft.WindowsAzure.StorageClient;
using System.Configuration;
using System.Xml;
using System.IO;
using System.Threading;

namespace WordPressShared
{
    public class RoleStartupUtils
    {

        /// <summary>
        /// Mounts the VHD as a local drive
        /// </summary>
        /// <returns>A string with the path of the local mounted drive</returns>
        public static CloudDrive MountCloudDrive(string StorageConnectionString, string LocalResourceName, string ImageStoreBlobUri, string driveSize)
        {
            CloudDrive drive = null;

            try
            {
                // initialize storage account configuration setting publisher
                CloudStorageAccount.SetConfigurationSettingPublisher((configName, configSetter) =>
                {
                    string connectionString = RoleEnvironment.GetConfigurationSettingValue(configName);
                    configSetter(connectionString);
                });


                LocalResource cache = RoleEnvironment.GetLocalResource(LocalResourceName);
                CloudDrive.InitializeCache(cache.RootPath.TrimEnd('\\'), cache.MaximumSizeInMegabytes - 8);

                // retrieve storage account 
                CloudStorageAccount account = CloudStorageAccount.FromConfigurationSetting("AcceleratorConnectionString");

                // retrieve URI for the page blob that contains the cloud drive from configuration settings 
                string imageStoreBlobUri = RoleEnvironment.GetConfigurationSettingValue("ImageStoreBlobUri");

                // create the Windows Azure drive and its associated page blob
                drive = account.CreateCloudDrive(imageStoreBlobUri);

                try
                {
                    drive.Create(int.Parse(driveSize));

                }
                catch (CloudDriveException ex1)
                {
                    // drive already exists
                }
                // mount the drive and initialize the application with the path to the image store on the Azure drive
                string imageStorePath = drive.Mount(cache.MaximumSizeInMegabytes - 50, DriveMountOptions.Force);

            }
            catch (CloudDriveException driveException)
            {
                Trace.WriteLine("Error Application_Start: " + driveException.Message);
            }
            catch (Exception ex)
            {
                Trace.WriteLine("Error Application_Start: " + ex.Message);
            }


            return drive;
        }


        /// <summary>
        /// Maps a Network Drive (SMB Server Share)
        /// </summary>
        /// <param name="localPath">Drive name</param>
        /// <param name="shareName">Share name on the SMB server</param>
        /// <param name="userName">Username for mapping the network drive</param>
        /// <param name="password">Password for mapping the network drive</param>
        /// <returns>True if the mapping successfull</returns>
        public static bool MapNetworkDrive(bool SMBMode, string MachineIP, string localPath, string shareName, string userName, string password)
        {
            bool res = false;
            try
            {
                int exitCode = 1;

                // Borro la unidad de red
                try
                {
                    string error, output;
                    ExecuteCommand("net.exe", " use " + localPath + "  /delete", out output, out error, 20000);
                    System.Threading.Thread.Sleep(500);
                }
                catch (Exception ex1)
                {
                }

                // The code here mounts the drive shared out by the server worker role
                // The mounted drive contains DotNetNuke contents and published through the
                // service definition file
                int i = 0;
                exitCode = 1;
                while (exitCode != 0)
                {
                    string error, output;

                    //Trace.TraceInformation("Mapping network drive...");

                    //Trace.TraceInformation("Trying to connect the drive to SMB role instance " + server.Id + ")");

                    MachineIP = "\\\\" + MachineIP + "\\";
                    exitCode = ExecuteCommand("net.exe", " use " + localPath + " " + MachineIP + shareName + " " + password + " /user:"
                        + userName, out output, out error, 20000);
                    
                    if (exitCode != 0)
                    {
                        try
                        {
                            //Trace.TraceWarning("Error mapping network drive, retrying in 10 seconds error msg:" + error);
                            // clean up stale mounts and retry 
                            //Trace.TraceInformation("DNNAzure - Cleaning up stale mounts...");
                            ExecuteCommand("net.exe", " use " + localPath + "  /delete", out output, out error, 20000);
                            System.Threading.Thread.Sleep(10000);
                            i++;
                        }
                        catch (Exception ex1)
                        {
                        }
                        if (i > 3) break;
                    }
                }
                
                if (exitCode == 0)
                {
                    Trace.TraceInformation("Success: mapped network drive" + MachineIP + shareName);
                    res = true;
                }
                else
                    res = false;
            }
            catch (Exception ex)
            {
                
                res = false;
            }
           

            return res;
        }


        /// <summary>
        /// Shares a local folder
        /// </summary>
        /// <param name="userName">Username to share the drive with full access permissions</param>
        /// <param name="RDPuserName">(Optional) Second username to grant full access permissions</param>
        /// <param name="path">Path to share</param>
        /// <param name="shareName">Share name</param>
        /// <returns>Returns 0 if success</returns>
        public static int ShareLocalFolder(string userName, string RDPuserName, string path, string shareName)
        {
            try
            {
                int exitCode;
                string error;
                //Trace.TraceInformation("Sharing local folder " + path);
                string GrantRDPUserName = "";
                if (RDPuserName != "")
                    GrantRDPUserName = " /Grant:" + RDPuserName + ",full";
                exitCode = ExecuteCommand("net.exe", " share " + shareName + "=" + path + " /Grant:" + userName + ",full" + GrantRDPUserName, out error, 10000);

                if (exitCode != 0)
                    //Log error and continue since the drive may already be shared
                    Trace.TraceWarning("Error creating fileshare, error msg:" + error, "Warning");
                return exitCode;
            }catch
            {
                return 1;
            }
        }

        /// <summary>
        /// Enables SMB traffic through the firewall
        /// </summary>
        /// <returns>Returns 0 if success</returns>
        public static int EnableSMBFirewallTraffic()
        {
            int exitCode;
            string error;
            //Enable SMB traffic through the firewall
            //Trace.TraceInformation("Enable SMB traffic through the firewall");
            exitCode = ExecuteCommand("netsh.exe", "firewall set service type=fileandprint mode=enable scope=all", out error, 10000);
            if (exitCode != 0)
            {
                //Trace.TraceError("Error setting up firewall, error msg:" + error);
            }
            return exitCode;
        }

        /// <summary>
        /// Creates a user account on the local machine
        /// </summary>
        /// <param name="userName">Name for the user account</param>
        /// <param name="password">Password for the user account</param>
        /// <returns>Returns 0 if success</returns>
        public static int CreateUserAccount(string userName, string password)
        {
            int exitCode;
            string error;

            //Create the user account    
            //Trace.TraceInformation("Creating user account for sharing");
            exitCode = ExecuteCommand("net.exe", "user " + userName + " " + password + " /add", out error, 10000);
            if (exitCode != 0)
            {
                //Log error and continue since the user account may already exist
                Trace.TraceWarning("Error creating user account, error msg:" + error);
            }
            return exitCode;
        }


        /// <summary>
        /// Executes an external .exe command
        /// </summary>
        /// <param name="exe">EXE path</param>
        /// <param name="arguments">Arguments</param>
        /// <param name="output">Output of the command</param>
        /// <param name="error">Contents of the error results if fails</param>
        /// <param name="timeout">Timeout for executing the command in milliseconds</param>
        /// <returns>Exit code</returns>
        public static int ExecuteCommand(string exe, string arguments, out string output, out string error, int timeout)
        {
            Process p = new Process();
            int exitCode;
            p.StartInfo.FileName = exe;
            p.StartInfo.Arguments = arguments;
            p.StartInfo.CreateNoWindow = true;
            p.StartInfo.UseShellExecute = false;
            p.StartInfo.RedirectStandardError = true;
            p.StartInfo.RedirectStandardOutput = true;
            p.Start();
            error = p.StandardError.ReadToEnd();
            output = p.StandardOutput.ReadToEnd();
            p.WaitForExit(timeout);
            exitCode = p.ExitCode;
            p.Close();

            return exitCode;
        }

        /// <summary>
        /// Executes an external .exe command
        /// </summary>
        /// <param name="exe">EXE path</param>
        /// <param name="arguments">Arguments</param>
        /// <param name="error">Contents of the error results if fails</param>
        /// <param name="timeout">Timeout for executing the command in milliseconds</param>
        /// <returns>Exit code</returns>
        public static int ExecuteCommand(string exe, string arguments, out string error, int timeout)
        {
            string output;
            return ExecuteCommand(exe, arguments, out output, out error, timeout);
        }


    }
}
